using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using System.Net.Http;
using System.Net.Http.Headers;

namespace Terra.Core.Common.Utils;

/// <summary>
/// 文件操作工具类
/// </summary>
public static class FileUtils
{
    #region 文件检查

    /// <summary>
    /// 检查文件是否存在
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <returns>是否存在</returns>
    public static bool Exists(string filePath)
    {
        return !string.IsNullOrEmpty(filePath) && File.Exists(filePath);
    }

    /// <summary>
    /// 确保文件目录存在,如果不存在则创建
    /// </summary>
    /// <param name="filePath">文件路径</param>
    public static void EnsureDirectoryExists(string filePath)
    {
        if (string.IsNullOrEmpty(filePath)) return;

        string directoryPath = Path.GetDirectoryName(filePath);
        if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath))
        {
            Directory.CreateDirectory(directoryPath);
        }
    }

    #endregion

    #region 文件读取

    /// <summary>
    /// 读取文件所有文本
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <param name="encoding">编码格式,默认UTF8</param>
    /// <returns>文件内容</returns>
    public static string ReadAllText(string filePath, Encoding encoding = null)
    {
        if (!Exists(filePath)) return string.Empty;
        encoding ??= Encoding.UTF8;
        return File.ReadAllText(filePath, encoding);
    }

    /// <summary>
    /// 异步读取文件所有文本
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <param name="encoding">编码格式,默认UTF8</param>
    /// <returns>文件内容</returns>
    public static async Task<string> ReadAllTextAsync(string filePath, Encoding encoding = null)
    {
        if (!Exists(filePath)) return string.Empty;
        encoding ??= Encoding.UTF8;
        return await File.ReadAllTextAsync(filePath, encoding);
    }

    /// <summary>
    /// 读取文件所有行
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <param name="encoding">编码格式,默认UTF8</param>
    /// <returns>文件行集合</returns>
    public static string[] ReadAllLines(string filePath, Encoding encoding = null)
    {
        if (!Exists(filePath)) return Array.Empty<string>();
        encoding ??= Encoding.UTF8;
        return File.ReadAllLines(filePath, encoding);
    }

    /// <summary>
    /// 异步读取文件所有行
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <param name="encoding">编码格式,默认UTF8</param>
    /// <returns>文件行集合</returns>
    public static async Task<string[]> ReadAllLinesAsync(string filePath, Encoding encoding = null)
    {
        if (!Exists(filePath)) return Array.Empty<string>();
        encoding ??= Encoding.UTF8;
        return await File.ReadAllLinesAsync(filePath, encoding);
    }

    #endregion

    #region 文件写入

    /// <summary>
    /// 写入文本到文件
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <param name="content">文件内容</param>
    /// <param name="encoding">编码格式,默认UTF8</param>
    /// <param name="append">是否追加,默认false</param>
    public static void WriteAllText(string filePath, string content, Encoding encoding = null, bool append = false)
    {
        if (string.IsNullOrEmpty(filePath)) return;

        encoding ??= Encoding.UTF8;
        EnsureDirectoryExists(filePath);

        if (append && Exists(filePath))
        {
            File.AppendAllText(filePath, content, encoding);
        }
        else
        {
            File.WriteAllText(filePath, content, encoding);
        }
    }

    /// <summary>
    /// 异步写入文本到文件
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <param name="content">文件内容</param>
    /// <param name="encoding">编码格式,默认UTF8</param>
    /// <param name="append">是否追加,默认false</param>
    public static async Task WriteAllTextAsync(string filePath, string content, Encoding encoding = null, bool append = false)
    {
        if (string.IsNullOrEmpty(filePath)) return;

        encoding ??= Encoding.UTF8;
        EnsureDirectoryExists(filePath);

        if (append && Exists(filePath))
        {
            await File.AppendAllTextAsync(filePath, content, encoding);
        }
        else
        {
            await File.WriteAllTextAsync(filePath, content, encoding);
        }
    }

    /// <summary>
    /// 写入多行文本到文件
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <param name="lines">文本行集合</param>
    /// <param name="encoding">编码格式,默认UTF8</param>
    /// <param name="append">是否追加,默认false</param>
    public static void WriteAllLines(string filePath, IEnumerable<string> lines, Encoding encoding = null, bool append = false)
    {
        if (string.IsNullOrEmpty(filePath)) return;

        encoding ??= Encoding.UTF8;
        EnsureDirectoryExists(filePath);

        if (append && Exists(filePath))
        {
            File.AppendAllLines(filePath, lines, encoding);
        }
        else
        {
            File.WriteAllLines(filePath, lines, encoding);
        }
    }

    /// <summary>
    /// 异步写入多行文本到文件
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <param name="lines">文本行集合</param>
    /// <param name="encoding">编码格式,默认UTF8</param>
    /// <param name="append">是否追加,默认false</param>
    public static async Task WriteAllLinesAsync(string filePath, IEnumerable<string> lines, Encoding encoding = null, bool append = false)
    {
        if (string.IsNullOrEmpty(filePath)) return;

        encoding ??= Encoding.UTF8;
        EnsureDirectoryExists(filePath);

        if (append && Exists(filePath))
        {
            await File.AppendAllLinesAsync(filePath, lines, encoding);
        }
        else
        {
            await File.WriteAllLinesAsync(filePath, lines, encoding);
        }
    }

    #endregion

    #region 文件操作

    /// <summary>
    /// 复制文件
    /// </summary>
    /// <param name="sourceFile">源文件</param>
    /// <param name="destFile">目标文件</param>
    /// <param name="overwrite">是否覆盖,默认false</param>
    /// <returns>是否成功</returns>
    public static bool Copy(string sourceFile, string destFile, bool overwrite = false)
    {
        try
        {
            if (!Exists(sourceFile)) return false;

            EnsureDirectoryExists(destFile);
            File.Copy(sourceFile, destFile, overwrite);
            return true;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// 移动文件
    /// </summary>
    /// <param name="sourceFile">源文件</param>
    /// <param name="destFile">目标文件</param>
    /// <param name="overwrite">是否覆盖,默认false</param>
    /// <returns>是否成功</returns>
    public static bool Move(string sourceFile, string destFile, bool overwrite = false)
    {
        try
        {
            if (!Exists(sourceFile)) return false;

            if (overwrite && Exists(destFile))
            {
                File.Delete(destFile);
            }

            EnsureDirectoryExists(destFile);
            File.Move(sourceFile, destFile);
            return true;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// 删除文件
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <returns>是否成功</returns>
    public static bool Delete(string filePath)
    {
        try
        {
            if (!Exists(filePath)) return false;
            File.Delete(filePath);
            return true;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// 获取文件大小
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <returns>文件大小(字节)</returns>
    public static long GetFileSize(string filePath)
    {
        if (!Exists(filePath)) return 0;
        return new FileInfo(filePath).Length;
    }

    /// <summary>
    /// 获取文件扩展名
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <returns>扩展名</returns>
    public static string GetExtension(string filePath)
    {
        if (string.IsNullOrEmpty(filePath)) return string.Empty;
        return Path.GetExtension(filePath);
    }

    /// <summary>
    /// 获取文件名(不含扩展名)
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <returns>文件名</returns>
    public static string GetFileNameWithoutExtension(string filePath)
    {
        if (string.IsNullOrEmpty(filePath)) return string.Empty;
        return Path.GetFileNameWithoutExtension(filePath);
    }

    /// <summary>
    /// 获取文件名(含扩展名)
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <returns>文件名</returns>
    public static string GetFileName(string filePath)
    {
        if (string.IsNullOrEmpty(filePath)) return string.Empty;
        return Path.GetFileName(filePath);
    }

    #endregion

    #region 文件搜索

    /// <summary>
    /// 获取指定目录下所有文件
    /// </summary>
    /// <param name="directoryPath">目录路径</param>
    /// <param name="searchPattern">搜索模式,默认*.*</param>
    /// <param name="searchOption">搜索选项,默认当前目录</param>
    /// <returns>文件路径集合</returns>
    public static string[] GetFiles(string directoryPath, string searchPattern = "*.*", SearchOption searchOption = SearchOption.TopDirectoryOnly)
    {
        if (string.IsNullOrEmpty(directoryPath) || !Directory.Exists(directoryPath))
            return Array.Empty<string>();

        return Directory.GetFiles(directoryPath, searchPattern, searchOption);
    }

    /// <summary>
    /// 获取指定目录下所有文件信息
    /// </summary>
    /// <param name="directoryPath">目录路径</param>
    /// <param name="searchPattern">搜索模式,默认*.*</param>
    /// <param name="searchOption">搜索选项,默认当前目录</param>
    /// <returns>文件信息集合</returns>
    public static FileInfo[] GetFileInfos(string directoryPath, string searchPattern = "*.*", SearchOption searchOption = SearchOption.TopDirectoryOnly)
    {
        if (string.IsNullOrEmpty(directoryPath) || !Directory.Exists(directoryPath))
            return Array.Empty<FileInfo>();

        var directory = new DirectoryInfo(directoryPath);
        return directory.GetFiles(searchPattern, searchOption);
    }

    #endregion

    #region 文件上传下载

    /// <summary>
    /// 保存上传的文件
    /// </summary>
    /// <param name="file">上传的文件</param>
    /// <param name="savePath">保存路径</param>
    /// <param name="overwrite">是否覆盖已存在的文件</param>
    /// <returns>是否成功</returns>
    public static async Task<bool> SaveUploadedFileAsync(IFormFile file, string savePath, bool overwrite = false)
    {
        try
        {
            Check.NotNull(file, nameof(file));
            Check.NotNullOrEmpty(savePath, nameof(savePath));

            if (file.Length == 0) return false;

            if (!overwrite && Exists(savePath)) return false;

            EnsureDirectoryExists(savePath);
            using var stream = new FileStream(savePath, FileMode.Create);
            await file.CopyToAsync(stream);
            return true;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// 下载文件到指定路径
    /// </summary>
    /// <param name="url">文件URL</param>
    /// <param name="savePath">保存路径</param>
    /// <param name="overwrite">是否覆盖已存在的文件</param>
    /// <returns>是否成功</returns>
    public static async Task<bool> DownloadFileAsync(string url, string savePath, bool overwrite = false)
    {
        try
        {
            Check.NotNullOrEmpty(url, nameof(url));
            Check.NotNullOrEmpty(savePath, nameof(savePath));

            if (!overwrite && Exists(savePath)) return false;

            using var httpClient = new HttpClient();
            using var response = await httpClient.GetAsync(url);
            if (!response.IsSuccessStatusCode) return false;

            EnsureDirectoryExists(savePath);
            using var stream = await response.Content.ReadAsStreamAsync();
            using var fileStream = new FileStream(savePath, FileMode.Create);
            await stream.CopyToAsync(fileStream);
            return true;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// 获取文件的 MIME 类型
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <returns>MIME 类型</returns>
    public static string GetMimeType(string filePath)
    {
        var extension = GetExtension(filePath)?.ToLowerInvariant();
        return extension switch
        {
            ".txt" => "text/plain",
            ".pdf" => "application/pdf",
            ".doc" => "application/msword",
            ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            ".xls" => "application/vnd.ms-excel",
            ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            ".png" => "image/png",
            ".jpg" => "image/jpeg",
            ".jpeg" => "image/jpeg",
            ".gif" => "image/gif",
            ".csv" => "text/csv",
            ".zip" => "application/zip",
            ".rar" => "application/x-rar-compressed",
            ".mp4" => "video/mp4",
            ".mp3" => "audio/mpeg",
            _ => "application/octet-stream"
        };
    }

    /// <summary>
    /// 创建文件下载的 HTTP 响应
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <param name="fileName">下载显示的文件名,为空则使用原文件名</param>
    /// <returns>HTTP 响应消息</returns>
    public static HttpResponseMessage CreateDownloadResponse(string filePath, string fileName = null)
    {
        Check.NotNullOrEmpty(filePath, nameof(filePath));
        if (!Exists(filePath)) throw new FileNotFoundException("文件不存在", filePath);

        var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
        var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
        response.Content = new StreamContent(stream);

        fileName ??= GetFileName(filePath);
        var contentType = GetMimeType(filePath);
        response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
        response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
        {
            FileName = fileName
        };

        return response;
    }

    /// <summary>
    /// 验证上传的文件
    /// </summary>
    /// <param name="file">上传的文件</param>
    /// <param name="maxSize">最大文件大小(字节)</param>
    /// <param name="allowedExtensions">允许的文件扩展名</param>
    /// <returns>验证结果</returns>
    public static (bool IsValid, string ErrorMessage) ValidateUploadedFile(
        IFormFile file,
        long maxSize = 10485760, // 默认10MB
        string[] allowedExtensions = null)
    {
        if (file == null || file.Length == 0)
            return (false, "文件不能为空");

        if (file.Length > maxSize)
            return (false, $"文件大小不能超过 {maxSize / 1024 / 1024}MB");

        if (allowedExtensions != null && allowedExtensions.Length > 0)
        {
            var extension = Path.GetExtension(file.FileName)?.ToLowerInvariant();
            if (string.IsNullOrEmpty(extension) || !allowedExtensions.Contains(extension))
                return (false, "不支持的文件类型");
        }

        return (true, null);
    }

    #endregion
}